package org.example.framework.MiniApplicationContext;

import org.example.framework.BeanDefinition.BeanDefinition;
import org.example.framework.BeanDefinition.BeanProperty;
import org.example.framework.BeanDefinitionLoader.XmlBeanDefinitionLoader;
import org.example.framework.BeanDefinitionMap.BeanDefinitionMap;
import org.example.framework.BeanException.BeanException;

import java.lang.reflect.Method;

public class MiniApplicationContext extends AbstractApplicationContext {

    public MiniApplicationContext(String configLocation) throws Exception {
        super.configLocation = configLocation;
        beanDefinitionLoader = new XmlBeanDefinitionLoader();
        super.refresh();
    }

    @Override
    public Object getBean(String name) throws Exception {
        Object obj = singletonObjectMap.get(name);
        if (null != obj) {
            return obj;
        }
        BeanDefinitionMap map = beanDefinitionLoader.getMap();
        BeanDefinition beanDefinition = map.getBeanDefinition(name);
        if (null == beanDefinition) {
            throw new BeanException(BeanException.ErrorType.CLASS_NOTFOUND, "class not find in beans");
        }

        Class<?> clazz = beanDefinition.getBeanClass();
        Object beanObj = clazz.newInstance();

        for (BeanProperty beanProperty : beanDefinition.getPropertyList()) {
            String propertyValueName = beanProperty.getName();
            String ref = beanProperty.getRef();
            //System.out.println(ref);
            if (null != ref && !"".equals(ref.trim())) {
                Object bean = getBean(ref);
                String setMethodName = buildSetMethodName(propertyValueName);
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (method.getName().equals(setMethodName)) {
                        method.invoke(beanObj, bean);
                    }
                }
            }
        }
        singletonObjectMap.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        return clazz.cast(bean);
    }

    private String buildSetMethodName(String name) {
        if (null == name || "".equals(name.trim())) {
            return "";
        }
        String upperString = name.substring(0, 1).toUpperCase() + name.substring(1);
        return "set" + upperString;
    }
}
